﻿using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Main.Structure;
using Main.Substructure;

namespace Main.Database
{
    public static class Appointments
    {
        private static object _syncObject = new object();

        /// <summary>Counts how many appointments there are and then loads them all.</summary>
        public static bool Load()
        {
            try
            {
                FileStream FS; // The file stream used to read/write to a file. Null for now.
                BinaryReader BR; // The reader used to read binary from files. Null for now.
                // For every file in the appointment directory...
                foreach (var element in Directory.GetFiles(Hub.Configuration.APPOINTMENT_PATH))
                {
                    // Now we can create a new FileStream set to read the file we're looping through.
                    FS = new FileStream(element, FileMode.Open, FileAccess.Read);
                    // Make a binary reader to read that file.
                    BR = new BinaryReader(FS, Encoding.UTF8);
                    // Create a new appointment variable by reading the date ticks and notes saved.
                    long ticks = BR.ReadInt64();
                    int dataLen = BR.ReadInt32();
                    string data = Encoding.UTF8.GetString(BR.ReadBytes(dataLen));
                    Appointment appt = new Appointment(ticks, data);

                    // If they aren't closed, we can't edit them until the program is closed.
                    // You should always close streams and readers/writers once you're done with them.
                    // Since we're making a new stream and reader, might as well close/flush/dispose them.
                    #region Close File Streams/Readers
                    BR.Dispose();
                    BR.Close();
                    FS.Dispose();
                    FS.Close();
                    #endregion

                    Kernel.Appointments.TryAdd(appt.Ticks, appt); // Add the appointment to the pool

                    // If this is the first appointment loaded, assign the preview appoinment variable
                    if (Kernel.Appointments.Count == 1)
                        Hub.prevAppt = appt;
                }
                return true;
            }
            catch (Exception) { return false; }
        }

        /// <summary>Creates a new appointment file and adds it to the pool.</summary>
        /// <param name="appt">The appointment that's going to be added.</param>
        public static bool Add(Appointment appt)
        {
            try
            {
                var path = Hub.Configuration.APPOINTMENT_PATH + appt.Ticks + ".appt";

                // Check if the appointment has already been made before. If it hasn't been, continue.
                if (!File.Exists(path))
                {
                    // Create an empty file to use, and then close it so we can write to it.
                    File.Create(path).Close();

                    // Create a new FileStream of the file that we're going to read/write to.
                    // In this case, I specify that I'm only going to write to it.
                    FileStream FS = new FileStream(path, FileMode.Open, FileAccess.Write);
                    // We create a BinaryWriter to write binary to the file.
                    BinaryWriter BW = new BinaryWriter(FS, Encoding.UTF8);

                    BW.Write((long)appt.Ticks);
                    byte[] data = Encoding.UTF8.GetBytes(appt.Notes);
                    BW.Write(data.Length);
                    BW.Write(data);
                    // We need to close/flush/dispose of the stream/writer so we can use the file
                    // later without closing the program first
                    #region Stream/Writer Close
                    BW.Flush();
                    BW.Dispose();
                    BW.Close();
                    FS.Dispose();
                    FS.Close();
                    #endregion

                    Kernel.Appointments.TryAdd(appt.Ticks, appt); // Add this new appointment to the pool
                    return true;
                }
                // If the appointment as already been made before, run this code...
                else
                {
                    // Ask the user if they want to overwrite the appointment file.
                    DialogResult result = Utilities.Message("An appointment with this date and time already exists. Overwrite?", "Overwrite?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    // If so, run the code that's used for if the file doesn't exist, except delete the file first.
                    if (result == DialogResult.Yes)
                    {
                        File.Delete(path); // Gotta delete the file before we re-create it.
                        File.Create(path).Close();

                        FileStream FS = new FileStream(path, FileMode.Open, FileAccess.Write);
                        BinaryWriter BW = new BinaryWriter(FS, Encoding.UTF8);

                        BW.Write((long)appt.Ticks);
                        BW.Write(appt.Notes);
                        #region Stream/Writer Close
                        BW.Flush();
                        BW.Dispose();
                        BW.Close();
                        FS.Dispose();
                        FS.Close();
                        #endregion

                        Kernel.Appointments.TryAdd(appt.Ticks, appt);
                        return true;
                    }
                    else { return false; } // Because they chose not to overwrite, count that as an error.
                }
            }
            catch (Exception) { return false; }
        }

        public static bool Remove(Appointment appt)
        {
            lock (_syncObject)
            {
                try
                {
                    var path = Hub.Configuration.APPOINTMENT_PATH + appt.Ticks + ".appt";

                    if (File.Exists(path))
                    {
                        DialogResult result = Utilities.Message("Are you sure would like to delete the appointment for " + appt.Date, "Delete Appointment?", MessageBoxButtons.YesNo, MessageBoxIcon.Stop);
                        if (result == DialogResult.Yes)
                        {
                            File.Delete(path);
                            Kernel.Appointments.TryRemove(appt.Ticks, out appt);
                        }
                        else { return false; }
                    }
                    return true;
                }
                catch (Exception) { return false; }
            }
        }
    }
}
